import Decimal from '../../../../static/decimal.js'

// 对应decimal.js方法
const character = new Map([
  ['+', 'add'],
  ['-', 'sub'],
  ['*', 'mul'],
  ['/', 'div'],
  ['%', 'mod']
])

// 优先级
const priority = new Map([
  ['+', 1],
  ['-', 1],
  ['*', 2],
  ['/', 2],
  ['%', 2]
])

/**
 * 表达式计算 不包含括号优先级
 * @param {string} str 表达式
 **/
const _compute = function (str) {
  let characters = _getCharacters(str)
  let prouiruttArr = characters.map(c => priority.get(c) || 0)
  while (characters.length > 3 && prouiruttArr.length > 3) {
    // 找出优先级高的先计算
    const maxIndex = findArrayMaxIndex(prouiruttArr)
    let result
    // 计算完成把结果替换字符串表达式中的字符
    if (maxIndex !== -1) {
      const expression = `${characters[maxIndex - 1]}${characters[maxIndex]}${characters[maxIndex + 1]}`
      result = Decimal[character.get(characters[maxIndex])](characters[maxIndex - 1], characters[maxIndex + 1])
      console.debug(result.toString())
      str = str.replace(expression, result.toString())
      // 数组重新赋值改变长度
      characters = _getCharacters(str)
      prouiruttArr = characters.map(c => priority.get(c) || 0)
    } else {
      return result
    }
  }
  // 出循环只计算一次
  const index = findArrayMaxIndex(prouiruttArr)
  return Decimal[character.get(characters[index])](characters[index - 1], characters[index + 1])
}

/**
 * 字符匹配
 * 正则匹配 数字、负数、加乘除符号 减号会被匹配为负数 循环判断处理
 * @param {string} str 表达式字符串
 **/
const _getCharacters = function (str) {
  const characters = str.match(/(-(?=\d))?\d+(\.\d+)?|[-\+\/*\%]/g)
  // characters校验 考虑负数的情况 通过正则匹配负数而不考虑减号 再循环匹配减号做判断
  for (let i = 0; i < characters.length; i++) {
    if (characters[i].match(/-\d/g)) {
      // 匹配负数
      if (characters[i] && characters[i - 1] && i !== 0) {
        if (!character.get(characters[i - 1])) {
          // 如果负数上一个不为符号 则把该负数改为减号
          characters.splice(i + 1, 0, characters[i].replace('-', ''))
          characters.splice(i, 1, '-')
        }
      }
    }
  }
  return characters
}

/**
 * 找数组的最大值下标
 * @param {Array} arr
 **/
const findArrayMaxIndex = function (arr) {
  let max = 0
  let fIndex = -1
  for (let i = 0; i < arr.length; i++) {
    if (arr[i] > max) {
      fIndex = i
      max = arr[i]
    }
  }
  return fIndex
}

/**
 * 括号优先级的处理
 */
const _matchBracket = function (str) {
  if (!str) {
    throw new Error('空字符')
  }
  // 检查括号的数量是否相等
  const checkArr = [str.match(/\(/g), str.match(/\)/g)]
  if (checkArr[0] && checkArr[1] && checkArr[0].length !== checkArr[1].length) {
    throw new Error('Invalid argument')
  }
  // 用正则检查是否包含多个括号
  const matchEx = str.match(/\([^()]+\)/g)
  matchEx &&
  matchEx.forEach(ex => {
    str = str.replace(ex, _compute(ex.replace(/\(|\)/g, '')).toString())
  })

  // 递归判断是否有括号 先算括号内的表达式
  if (str.indexOf('(') !== -1 && str.lastIndexOf(')') !== -1) {
    const res = _matchBracket(str.slice(str.indexOf('(') + 1, str.lastIndexOf(')')))
    // 如果有结果 把结果替换原本的表达式中的括号内容
    if (res) {
      str = str.replace(str.slice(str.indexOf('('), str.lastIndexOf(')') + 1), res)
    }
  }
  // 如果没有加减乘除运算 直接返回结果
  if (_getCharacters(str).length < 2) {
    return str
  }
  return _compute(str).toString()
}

/**
 * 加减乘除计算
 **/
const compute = function (str) {
  str = str.replaceAll(' ', '') // 去空格
  try {
    // 如果存在括号
    if (str.indexOf('(') !== -1 && str.lastIndexOf(')') !== -1) {
      return _matchBracket(str)
    }
    return _compute(str)
  } catch (e) {
    console.error(e)
    return NaN
  }
}
export default compute
